package com.deluxelx.soul.inn.service.course.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deluxelx.soul.inn.bean.counselor.Counselor;
import com.deluxelx.soul.inn.bean.course.Course;
import com.deluxelx.soul.inn.bean.course.CourseDTO;
import com.deluxelx.soul.inn.bean.course.CourseDetailVO;
import com.deluxelx.soul.inn.bean.course.CourseVO;
import com.deluxelx.soul.inn.common.enums.NavbarEnum;
import com.deluxelx.soul.inn.common.param.CollectedParam;
import com.deluxelx.soul.inn.common.util.DateTimeUtil;
import com.deluxelx.soul.inn.common.util.RedisUtil;
import com.deluxelx.soul.inn.common.util.supportIds.SnowflakeId;
import com.deluxelx.soul.inn.mapper.common.IndexDataSupport;
import com.deluxelx.soul.inn.mapper.counselor.CounselorMapper;
import com.deluxelx.soul.inn.mapper.course.CourseMapper;
import com.deluxelx.soul.inn.service.common.FollowRelationService;
import com.deluxelx.soul.inn.service.course.CourseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.deluxelx.soul.inn.common.constant.CourseConstant.*;
import static com.deluxelx.soul.inn.common.constant.IndexType.COURSE;

/**
 * 课程服务实现类
 *
 * @author: zihao.liao
 * @date: 2024/1/15 17:02
 */
@Service
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private IndexDataSupport indexDataSupport;

    @Resource
    private CounselorMapper counselorMapper;

    @Resource
    private FollowRelationService followRelationService;

    @Resource
    private SnowflakeId snowflake;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public List<CourseVO> fetchIndexCourseList() {
        List<String> indexCourseIds = indexDataSupport.selectIndexDataByType(COURSE);
        if (CollectionUtil.isEmpty(indexCourseIds)) {
            return Collections.emptyList();
        }
        return courseMapper.selectCourseListByIds(indexCourseIds);
    }

    @Override
    public List<CourseVO> fetchMyFollowCourse(String userId) {
        List<String> courseIds = followRelationService.getMyFollowIds(userId, COURSE_FOLLOW_KEY);
        if (CollectionUtil.isEmpty(courseIds)) {
            return Collections.emptyList();
        }
        List<CourseVO> courseVOS = courseMapper.selectCourseListByIds(courseIds);
        buildStandardCourseVO(courseVOS);
        return courseVOS;
    }

    @Override
    public List<CourseVO> fetchSearchCourseList(String keyword) {
        List<CourseVO> courseVOS = courseMapper.selectListByFuzzySearch(keyword);
        buildStandardCourseVO(courseVOS);
        return courseVOS;
    }

    @Override
    public List<CourseVO> fetchCourseListByCounselor(String counselorId) {
        List<CourseVO> courseVOS = courseMapper.selectCourseListByCounselorId(counselorId);
        buildStandardCourseVO(courseVOS);
        return courseVOS;
    }

    @Override
    public List<CourseVO> fetchCourseListByType(String typeId) {
        if (StrUtil.isBlank(typeId)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Course::getType, typeId)
                .select(Course::getId);
        List<Course> courseList = courseMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(courseList)) {
            return Collections.emptyList();
        }
        List<CourseVO> courseVOS = courseMapper.selectCourseListByIds(courseList.stream()
                .map(Course::getId)
                .collect(Collectors.toList()));
        if (CollectionUtil.isEmpty(courseVOS)) {
            return Collections.emptyList();
        }
        buildStandardCourseVO(courseVOS);
        return courseVOS;
    }

    @Override
    public CourseDetailVO fetchCourseDetail(String courseId) {
        Course course = courseMapper.selectById(courseId);
        if (null == course || null == course.getCounselorId()) {
            log.error("课程不存在或不符合规范：" + courseId);
            return null;
        }
        Counselor counselor = counselorMapper.selectById(course.getCounselorId());
        if (null == counselor) {
            log.error("该【" + courseId + "】课程的咨询师查询不到");
            return null;
        }
        CourseDetailVO courseDetailVO = new CourseDetailVO();
        courseDetailVO.setId(course.getId());
        courseDetailVO.setVideoUrl(course.getVideoUrl());
        courseDetailVO.setAuthorAvatar(counselor.getAvatar());
        courseDetailVO.setAuthorName(counselor.getName());
        courseDetailVO.setPublishTimeStr(DateTimeUtil.getStandardDate(course.getPublishTime()));
        courseDetailVO.setName(course.getName());
        courseDetailVO.setDetail(course.getDetail());
        courseDetailVO.setBacImg(course.getBacImg());
        Integer collectNum = redisUtil.get(buildFollowCourseKey(course.getId()), Integer.class);
        if (null != collectNum) {
            courseDetailVO.setCollectNum(collectNum);
        } else {
            courseDetailVO.setCollectNum(course.getCollectNum());
        }
        String key = buildPlayCourseKey(courseId);
        Integer playNum = redisUtil.get(key, Integer.class);
        if (null != playNum) {
            courseDetailVO.setPlayNum(playNum);
            redisUtil.incr(key, 1);
        } else {
            courseDetailVO.setPlayNum(course.getPlayNum() + 1);
            redisUtil.set(key, course.getPlayNum() + 1, COURSE_CACHE_EXPIRE_TIME);
        }
        return courseDetailVO;
    }

    @Override
    public Boolean isCollectCourse(CollectedParam param) {
        if (param == null || StrUtil.isEmpty(param.getUserId()) || StrUtil.isEmpty(param.getCourseId())) {
            return Boolean.FALSE;
        }
        String key = buildFollowCourseKey(param);
        Integer flag = redisUtil.get(key, Integer.class);
        if (null == flag) {
            Integer isSuccess = followRelationService.checkFollow(param);
            if (isSuccess > 0) {
                redisUtil.set(key, 1, COURSE_CACHE_EXPIRE_TIME);
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        } else if (0 == flag) {
            return Boolean.FALSE;
        } else if (1 == flag) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Boolean followCourse(CollectedParam param) {
        if (param == null || StrUtil.isEmpty(param.getUserId()) || StrUtil.isEmpty(param.getCourseId())) {
            return Boolean.FALSE;
        }
        try {
            String key1 = buildFollowCourseKey(param);
            boolean bool1 = redisUtil.set(key1, 1, COURSE_CACHE_EXPIRE_TIME);
            String key2 = buildFollowCourseKey(param.getCourseId());
            boolean bool2;
            if (redisUtil.hasKey(key2)) {
                redisUtil.incr(key2, 1);
                bool2 = redisUtil.expire(key2, COURSE_CACHE_EXPIRE_TIME);
            } else {
                Course course = courseMapper.selectById(param.getCourseId());
                if (null == course) {
                    return Boolean.FALSE;
                }
                bool2 = redisUtil.set(key2, course.getCollectNum() + 1, COURSE_CACHE_EXPIRE_TIME);
            }
            return bool1 && bool2;
        } catch (Exception e) {
            log.error("收藏课程失败：" + e.getMessage());
            return Boolean.FALSE;
        }
    }

    @Override
    public Boolean unFollowCourse(CollectedParam param) {
        if (param == null || StrUtil.isEmpty(param.getUserId()) || StrUtil.isEmpty(param.getCourseId())) {
            return Boolean.FALSE;
        }
        try {
            String key1 = buildFollowCourseKey(param);
            boolean bool1 = false;
            String key2 = buildFollowCourseKey(param.getCourseId());
            if (!redisUtil.hasKey(key1)) {
                Integer isSuccess = followRelationService.checkFollow(param);
                if (isSuccess > 0) {
                    bool1 = redisUtil.set(key1, 0, COURSE_CACHE_EXPIRE_TIME);
                }
            } else {
                bool1 = redisUtil.set(key1, 0, COURSE_CACHE_EXPIRE_TIME);
            }
            if (!bool1) {
                return Boolean.FALSE;
            }
            if (redisUtil.hasKey(key2)) {
                redisUtil.decr(key2, 1);
                return redisUtil.expire(key2, COURSE_CACHE_EXPIRE_TIME);
            } else {
                Course course = courseMapper.selectById(param.getCourseId());
                if (null == course) {
                    return Boolean.FALSE;
                }
                return redisUtil.set(key2, course.getCollectNum() - 1, COURSE_CACHE_EXPIRE_TIME);
            }
        } catch (Exception e) {
            log.error("取消收藏课程失败：" + e.getMessage());
            return Boolean.FALSE;
        }
    }

    @Override
    public String saveCourse(CourseDTO param) {
        LocalDateTime now = LocalDateTime.now();
        String counselorId = param.getCounselorId();
        Course course = new Course();
        course.setId(snowflake.nextStrId());
        course.setName(param.getTitle());
        course.setDetail(param.getText());
        course.setVideoUrl(param.getVideoUrl());
        course.setType(NavbarEnum.getCodeByName(param.getType()));
        course.setCounselorId(counselorId);
        course.setPublishTime(now);
        course.setCreateTime(now);
        course.setCreateUser(counselorId);
        course.setUpdateTime(now);
        course.setUpdateUser(counselorId);
        if (courseMapper.insert(course) > 0) {
            return course.getId();
        }
        return null;
    }

    @Override
    public Boolean modifyCourse(CourseDTO param) {
        if (StrUtil.isBlank(param.getCourseId())) {
            return false;
        }
        return this.lambdaUpdate()
                .set(StrUtil.isNotBlank(param.getTitle()), Course::getName, param.getTitle())
                .set(StrUtil.isNotBlank(param.getText()), Course::getDetail, param.getText())
                .set(StrUtil.isNotBlank(param.getType()), Course::getType, param.getType())
                .set(StrUtil.isNotBlank(param.getVideoUrl()), Course::getVideoUrl, param.getVideoUrl())
                .set(Course::getUpdateTime, LocalDateTime.now())
                .eq(Course::getId, param.getCourseId())
                .update();
    }

    @Override
    public Boolean removeCourse(String courseId) {
        if (StrUtil.isBlank(courseId)) {
            return false;
        }
        return this.lambdaUpdate()
                .set(Course::getDeleteFlag, 1)
                .eq(Course::getId, courseId)
                .update();
    }

    private void buildStandardCourseVO(List<CourseVO> courseVOList) {
        courseVOList.forEach(item -> {
            String title = item.getName();
            if (title.length() > 26) {
                item.setName(title.substring(0, 26) + "...");
            }
            Integer collectNum = redisUtil.get(buildFollowCourseKey(item.getId()), Integer.class);
            if (null != collectNum) {
                item.setCollectNum(collectNum);
            }
            Integer playNum = redisUtil.get(buildPlayCourseKey(item.getId()), Integer.class);
            if (null != playNum) {
                item.setPlayNum(playNum);
            }
        });
    }
}
